package com.example.oauth2.component;

import com.example.common.utils.Statistics;
import com.example.oauth2.utils.SecurityContextUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author <a href="nav1cat@outlook.com">nav1c</a>
 * @apiNote
 * @date 2024-01-25 11:08:32
 * @project study-cloud
 * @kit IntelliJ IDEA
 */
@Slf4j
public class PasswordAuthenticationConverter implements AuthenticationConverter {

    private static volatile PasswordAuthenticationConverter instance;

    private PasswordAuthenticationConverter(){
        Statistics.logInfo(log);
    }

    public static PasswordAuthenticationConverter getInstance(){
        if (instance == null) {
            synchronized (PasswordAuthenticationConverter.class){
                if (instance == null) {
                    instance = new PasswordAuthenticationConverter();
                }
            }
        }
        return instance;
    }

    @Override
    public Authentication convert(HttpServletRequest request) {
        Statistics.logInfo(log, "convert", request);
        final String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
        if (!AuthorizationGrantType.PASSWORD.equals(new AuthorizationGrantType(grantType))) {
            return null;
        }
        String username = request.getParameter("username");
        if (!StringUtils.hasText(username)){
            return null;
        }
        String password = request.getParameter("password");
        if (!StringUtils.hasText(password)){
            return null;
        }
        username = username.trim();
        Map<String, Object> params = new LinkedHashMap<>();
        params.put("username", username);
        params.put("password", password);
        //AbstractAuthenticationToken
        //为什么拿到的是Oauth2ClientAuthenticationToken 而不是 UserNamePasswordAuthenticationToken?
        Authentication clientPrincipal = SecurityContextUtils.getCurrentAuthentication();
        if (clientPrincipal instanceof OAuth2ClientAuthenticationToken oAuth2ClientAuthenticationToken){
            return new PasswordAuthenticationToken(oAuth2ClientAuthenticationToken, params);
        }
        throw new OAuth2AuthenticationException("error");
    }
}
